use crate::ast::{Code, Stmt, Expr, ExprKind, Op};
use crate::value::Value;
pub struct Evaler {
}

impl Evaler {

    pub fn new() -> Self {
        Evaler { }
    }

    pub fn eval(&self, code: Code) -> Value {
        let mut result = Value::Nil;
        for stmt in code.stmts {
            match stmt {
                Stmt::ExprStmt(expr) => {
                    result = self.eval_expr(expr);
                }
                Stmt::EOF => break,
            }
        }
        result
    }

    pub fn eval_expr(&self, expr: Expr) -> Value {

        match expr.kind {
            ExprKind::IntExpr(num) => {
                Value::Int(num)
            }
            ExprKind::FloatExpr(num) => {
                Value::Float(num)
            }
            ExprKind::BoolExpr(bool) => {
                Value::Bool(bool)
            }
            ExprKind::StrExpr(str) => {
                Value::Str(str)
            }
            ExprKind::BinaExpr(op, lhs, rhs) => {
                let lhs = self.eval_expr(*lhs);
                let rhs = self.eval_expr(*rhs);
                match op {
                    Op::Add => {
                        lhs.add(&rhs)
                    }
                    Op::Sub => {
                        lhs.sub(&rhs)
                    }
                    Op::Mul => {
                        lhs.mul(&rhs)
                    }
                    Op::Div => {
                        lhs.div(&rhs)
                    }
                }
            }
            ExprKind::EOF => {
                Value::Nil
            }
        }
    }
}

